package at.donalfonso.utility;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;

import org.mozartspaces.capi3.AnyCoordinator;
import org.mozartspaces.capi3.FifoCoordinator;
import org.mozartspaces.capi3.KeyCoordinator;
import org.mozartspaces.capi3.LabelCoordinator;
import org.mozartspaces.capi3.LindaCoordinator;
import org.mozartspaces.core.Capi;
import org.mozartspaces.core.ContainerReference;
import org.mozartspaces.core.DefaultMzsCore;
import org.mozartspaces.core.MzsCore;
import org.mozartspaces.core.MzsCoreException;
import org.mozartspaces.core.MzsConstants.Container;
import org.mozartspaces.core.MzsConstants.RequestTimeout;
import org.mozartspaces.notifications.NotificationManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class SpaceUtility {

	private int filiale;
	
	private MzsCore core = null;
	private Capi capi = null;
	private URI uri = null;
	private NotificationManager notificationManager = null;
	
	private MzsCore lieferCore = null;
	private Capi lieferCapi = null;
	private URI lieferUri = null;
	
	private ContainerReference kuecheInputContainer 		= null;
	private ContainerReference kuecheOutputContainer 		= null;
	private ContainerReference bestellungNeuContainer		= null;
	private ContainerReference bestellungOffenContainer 	= null;
	private ContainerReference bestellungZubContainer       = null;
	private ContainerReference bestellungFertigContainer 	= null;
	private ContainerReference zustellungContainer          = null;
	private ContainerReference saalContainer 				= null;
	private ContainerReference eingangContainer				= null;
	private ContainerReference gruppeSitzenContainer        = null;
	private ContainerReference gruppeWillBestellenContainer = null;
	private ContainerReference gruppeHatBestelltContainer   = null;
	private ContainerReference gruppeEssenContainer         = null;
	private ContainerReference gruppeWillBezahlenContainer  = null;
	private ContainerReference gruppeHatBezahltContainer    = null;
	private ContainerReference gruppeGegangenContainer      = null;
	private ContainerReference telefonContainer             = null;
	
	private final String KUECHE_INPUT_CONTAINERNAME       = "kueche_input";
	private final String KUECHE_OUTPUT_CONTAINERNAME      = "kueche_output";
	private final String BESTELLUNG_NEU_CONTAINERNAME     = "bestellungNeu";
	private final String BESTELLUNG_OFFEN_CONTAINERNAME	  = "bestellungOffen";
	private final String BESTELLUNG_ZUB_CONTAINERNAME     = "bestellungZub";
	private final String BESTELLUNG_FERTIG_CONTAINERNAME  = "bestellungFertig";
	private final String ZUSTELLUNG_CONTAINERNAME         = "zustellung";
	private final String SAAL_CONTAINERNAME	              = "saal";
	private final String EINGANG_CONTAINERNAME            = "eingang";
	private final String GRUPPE_SITZEN_CONTAINERNAME      = "gruppeSitzen";
	private final String GRUPPE_WILL_BESTELLEN_CONTAINERNAME = "gruppeWillBestellen";
	private final String GRUPPE_HAT_BESTELLT_CONTAINERNAME = "gruppeHatBestellt";
	private final String GRUPPE_ESSEN_CONTAINERNAME       = "gruppeEssen";
	private final String GRUPPE_WILL_BEZAHLEN_CONTAINERNAME = "gruppeWillBezahlen";
	private final String GRUPPE_HAT_BEZAHLT_CONTAINERNAME = "gruppeHatBezahlt";
	private final String GRUPPE_GEGANGEN_CONTAINERNAME    = "gruppeGegangen";
	private final String TELEFON_CONTAINERNAME            = "telefon";
	
	private static final String URI_STRING = "xvsm://localhost:";
	
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	/* Der Space ... unendliche weiten ... */
	public SpaceUtility(int filiale) {
		System.out.println("Space Utility ... initialisiert. Filiale: " + filiale);
		this.filiale = filiale;
	}
	
	/**
	 * Baut den Space initial auf und erzeugt alle relevanten Container.
	 */
	public void initSpace() {
		
		createCore();
				
		try {	
			saalContainer 			= getCapi().createContainer(SAAL_CONTAINERNAME, null, Container.UNBOUNDED, Arrays.asList(new AnyCoordinator()), Arrays.asList(new KeyCoordinator(), new LindaCoordinator()), null);
			eingangContainer		= getCapi().createContainer(EINGANG_CONTAINERNAME, null, Container.UNBOUNDED, Arrays.asList(new FifoCoordinator()), null, null);
			kuecheInputContainer 	= getCapi().createContainer(KUECHE_INPUT_CONTAINERNAME, null, Container.UNBOUNDED, Arrays.asList(new FifoCoordinator(), new AnyCoordinator()), null, null);
			kuecheOutputContainer 	= getCapi().createContainer(KUECHE_OUTPUT_CONTAINERNAME, null, Container.UNBOUNDED, Arrays.asList(new KeyCoordinator()), null, null);
			bestellungNeuContainer	= getCapi().createContainer(BESTELLUNG_NEU_CONTAINERNAME, null, Container.UNBOUNDED, Arrays.asList(new FifoCoordinator()), null, null);
			bestellungOffenContainer = getCapi().createContainer(BESTELLUNG_OFFEN_CONTAINERNAME, null, Container.UNBOUNDED, Arrays.asList(new FifoCoordinator()), Arrays.asList(new LindaCoordinator()), null);
			bestellungZubContainer  = getCapi().createContainer(BESTELLUNG_ZUB_CONTAINERNAME, null, Container.UNBOUNDED, Arrays.asList(new KeyCoordinator()), null, null);
			bestellungFertigContainer = getCapi().createContainer(BESTELLUNG_FERTIG_CONTAINERNAME, null, Container.UNBOUNDED, Arrays.asList(new LabelCoordinator()), null, null);
			zustellungContainer     = getCapi().createContainer(ZUSTELLUNG_CONTAINERNAME, null, Container.UNBOUNDED, Arrays.asList(new KeyCoordinator()), Arrays.asList(new LindaCoordinator()), null);
			gruppeSitzenContainer   = getCapi().createContainer(GRUPPE_SITZEN_CONTAINERNAME, null, Container.UNBOUNDED, Arrays.asList(new KeyCoordinator()), null, null);
			gruppeWillBestellenContainer = getCapi().createContainer(GRUPPE_WILL_BESTELLEN_CONTAINERNAME, null, Container.UNBOUNDED, Arrays.asList(new FifoCoordinator()), null, null);
			gruppeHatBestelltContainer = getCapi().createContainer(GRUPPE_HAT_BESTELLT_CONTAINERNAME, null, Container.UNBOUNDED, Arrays.asList(new KeyCoordinator()), null, null);
			gruppeEssenContainer    = getCapi().createContainer(GRUPPE_ESSEN_CONTAINERNAME, null, Container.UNBOUNDED, Arrays.asList(new KeyCoordinator()), null, null);
			gruppeWillBezahlenContainer = getCapi().createContainer(GRUPPE_WILL_BEZAHLEN_CONTAINERNAME, null, Container.UNBOUNDED, Arrays.asList(new FifoCoordinator()), null, null);
			gruppeHatBezahltContainer = getCapi().createContainer(GRUPPE_HAT_BEZAHLT_CONTAINERNAME, null, Container.UNBOUNDED, Arrays.asList(new KeyCoordinator()), null, null);
			gruppeGegangenContainer = getCapi().createContainer(GRUPPE_GEGANGEN_CONTAINERNAME, null, Container.UNBOUNDED, Arrays.asList(new FifoCoordinator()), null, null);
			telefonContainer        = getCapi().createContainer(TELEFON_CONTAINERNAME, null, Container.UNBOUNDED, Arrays.asList(new FifoCoordinator()), Arrays.asList(new LindaCoordinator()), null);
		} catch (MzsCoreException e) {
			logger.error("Could not initialize Space. ");
		}
		
	}
	

	public MzsCore getCore() {
		if (core == null) {
			core = DefaultMzsCore.newInstanceWithoutSpace();
		}
		return core;
	}
	
	public MzsCore getLieferCore() {
		if (lieferCore == null)
			lieferCore = DefaultMzsCore.newInstanceWithoutSpace();
		return lieferCore;
	}
	
	public MzsCore createCore() {
		core = DefaultMzsCore.newInstance(9876 + filiale);
		return core;
	}
	
	public MzsCore createLieferCore() {
		lieferCore = DefaultMzsCore.newInstance(9876);
		System.out.println("Space für Lieferkunden initialisiert.");
		return lieferCore;
	}
		
	public URI getUri() {
		if (uri == null) {
			try {
				int port = 9876 + filiale;
				uri = new URI(URI_STRING + Integer.toString(port));
			} catch (URISyntaxException e) {
				logger.error("Could not create uri.");
			}
		}
		return uri;
	}
	
	public URI getLieferUri() {
		if (lieferUri == null) {
			try {
				lieferUri = new URI(URI_STRING + Integer.toString(9876));
			} catch (URISyntaxException e) {
				logger.error("Could not create uri.");
			}
		}
		return lieferUri;
	}
	public Capi getCapi() {
		if (capi == null) {
			capi = new Capi(getCore());
		}
		
		return capi;
	}

	public Capi getLieferCapi() {
		if (lieferCapi == null) {
			lieferCapi = new Capi(getLieferCore());
		}
		
		return lieferCapi;
	}
	
	public ContainerReference getBestellungNeuContainer(){
		if (bestellungNeuContainer == null){
			try {
				bestellungNeuContainer = getCapi().lookupContainer(BESTELLUNG_NEU_CONTAINERNAME, getUri(), RequestTimeout.INFINITE, null);
			} catch (MzsCoreException e) {
				logger.error("Could not find Container: " + BESTELLUNG_NEU_CONTAINERNAME);
			}
		}
		return bestellungNeuContainer;
	}
	
	public ContainerReference getBestellungOffenContainer(){
		if (bestellungOffenContainer == null){
			try {
				bestellungOffenContainer = getCapi().lookupContainer(BESTELLUNG_OFFEN_CONTAINERNAME, getUri(), RequestTimeout.INFINITE, null);
			} catch (MzsCoreException e) {
				logger.error("Could not find Container: " + BESTELLUNG_OFFEN_CONTAINERNAME);
			}
		}
		return bestellungOffenContainer;
	}
	
	public ContainerReference getBestellungZubContainer(){
		if (bestellungZubContainer == null){
			try {
				bestellungZubContainer = getCapi().lookupContainer(BESTELLUNG_ZUB_CONTAINERNAME, getUri(), RequestTimeout.INFINITE, null);
			} catch (MzsCoreException e) {
				logger.error("Could not find Container: " + BESTELLUNG_ZUB_CONTAINERNAME);
			}
		}
		return bestellungZubContainer;
	}
	
	public ContainerReference getBestellungFertigContainer(){
		if (bestellungFertigContainer == null){
			try {
				bestellungFertigContainer = getCapi().lookupContainer(BESTELLUNG_FERTIG_CONTAINERNAME, getUri(), RequestTimeout.INFINITE, null);
			} catch (MzsCoreException e) {
				logger.error("Could not find Container: " + BESTELLUNG_FERTIG_CONTAINERNAME);
			}
		}
		return bestellungFertigContainer;
	}

	public ContainerReference getZustellungContainer() {
		if (zustellungContainer == null){
			try {
				zustellungContainer = getCapi().lookupContainer(ZUSTELLUNG_CONTAINERNAME, getUri(), RequestTimeout.INFINITE, null);
			} catch (MzsCoreException e) {
				logger.error("Could not find Container: " + ZUSTELLUNG_CONTAINERNAME);
			}
		}
		return zustellungContainer;
	}
	
	public ContainerReference getEingangContainer() {
		if (eingangContainer == null) {
			try {
				eingangContainer = getCapi().lookupContainer(EINGANG_CONTAINERNAME, getUri(), RequestTimeout.INFINITE, null);
			} catch (Exception e) {
				logger.error("Could not find Container: " + EINGANG_CONTAINERNAME);
			}
		}
		return eingangContainer;
	}
	
	public ContainerReference getSaalContainer(){
		if (saalContainer == null){
			try {
				saalContainer = getCapi().lookupContainer(SAAL_CONTAINERNAME, getUri(), RequestTimeout.INFINITE, null);
			} catch (Exception e) {
				logger.error("Could not find Container: " + SAAL_CONTAINERNAME);
			}
		}
		return saalContainer;
	}
	
	public ContainerReference getKuecheInputContainer(){
		if (kuecheInputContainer == null){
			try {
				kuecheInputContainer = getCapi().lookupContainer(KUECHE_INPUT_CONTAINERNAME, getUri(), RequestTimeout.INFINITE, null);
			} catch (Exception e) {
				logger.error("Could not find Container: kueche_input.");
			}
		}
		return kuecheInputContainer;
	}
	
	public ContainerReference getKuecheOutputContainer(){
		if (kuecheOutputContainer == null){
			try {
				kuecheOutputContainer = getCapi().lookupContainer(KUECHE_OUTPUT_CONTAINERNAME, getUri(), RequestTimeout.INFINITE, null);
			} catch (Exception e) {
				logger.error("Could not find Container: kueche_output.");
			}
		}		
		return kuecheOutputContainer;
	}	

	
	public ContainerReference getGruppeSitzenContainer() {
		if (gruppeSitzenContainer == null) {
			try {
				gruppeSitzenContainer = getCapi().lookupContainer(GRUPPE_SITZEN_CONTAINERNAME, getUri(), RequestTimeout.INFINITE, null);
			} catch (Exception e) {
				logger.error("Could not find Container: " + GRUPPE_SITZEN_CONTAINERNAME);
			}
		}		
		return gruppeSitzenContainer;
	}	
	
	public ContainerReference getGruppeWillBestellenContainer() {
		if (gruppeWillBestellenContainer == null) {
			try {
				gruppeWillBestellenContainer = getCapi().lookupContainer(GRUPPE_WILL_BESTELLEN_CONTAINERNAME, getUri(), RequestTimeout.INFINITE, null);
			} catch (Exception e) {
				logger.error("Could not find Container: " + GRUPPE_WILL_BESTELLEN_CONTAINERNAME);
			}
		}		
		return gruppeWillBestellenContainer;
	}	

	public ContainerReference getGruppeHatBestelltContainer() {
		if (gruppeHatBestelltContainer == null) {
			try {
				gruppeHatBestelltContainer = getCapi().lookupContainer(GRUPPE_HAT_BESTELLT_CONTAINERNAME, getUri(), RequestTimeout.INFINITE, null);
			} catch (Exception e) {
				logger.error("Could not find Container: " + GRUPPE_HAT_BESTELLT_CONTAINERNAME);
			}
		}		
		return gruppeHatBestelltContainer;
	}	
	
	public ContainerReference getGruppeEssenContainer() {
		if (gruppeEssenContainer == null) {
			try {
				gruppeEssenContainer = getCapi().lookupContainer(GRUPPE_ESSEN_CONTAINERNAME, getUri(), RequestTimeout.INFINITE, null);
			} catch (Exception e) {
				logger.error("Could not find Container: " + GRUPPE_ESSEN_CONTAINERNAME);
			}
		}		
		return gruppeEssenContainer;
	}
	
	public ContainerReference getGruppeWillBezahlenContainer() {
		if (gruppeWillBezahlenContainer == null) {
			try {
				gruppeWillBezahlenContainer = getCapi().lookupContainer(GRUPPE_WILL_BEZAHLEN_CONTAINERNAME, getUri(), RequestTimeout.INFINITE, null);
			} catch (Exception e) {
				logger.error("Could not find Container: " + GRUPPE_WILL_BEZAHLEN_CONTAINERNAME);
			}
		}		
		return gruppeWillBezahlenContainer;
	}

	public ContainerReference getGruppeHatBezahltContainer() {
		if (gruppeHatBezahltContainer == null) {
			try {
				gruppeHatBezahltContainer = getCapi().lookupContainer(GRUPPE_HAT_BEZAHLT_CONTAINERNAME, getUri(), RequestTimeout.INFINITE, null);
			} catch (Exception e) {
				logger.error("Could not find Container: " + GRUPPE_HAT_BEZAHLT_CONTAINERNAME);
			}
		}		
		return gruppeHatBezahltContainer;
	}
	
	public ContainerReference getGruppeGegangenContainer() {
		if (gruppeGegangenContainer == null) {
			try {
				gruppeGegangenContainer = getCapi().lookupContainer(GRUPPE_GEGANGEN_CONTAINERNAME, getUri(), RequestTimeout.INFINITE, null);
			} catch (Exception e) {
				logger.error("Could not find Container: " + GRUPPE_GEGANGEN_CONTAINERNAME);
			}
		}		
		return gruppeGegangenContainer;
	}
	
	public ContainerReference getTelefonContainer() {
		if (telefonContainer == null) {
			try {
				telefonContainer = getCapi().lookupContainer(TELEFON_CONTAINERNAME, getUri(), RequestTimeout.INFINITE, null);
			} catch (Exception e) {
				logger.error("Could not find Container: " + TELEFON_CONTAINERNAME);
			}
		}		
		return telefonContainer;
	}
	
	public NotificationManager getNotificationManager(){
		if (notificationManager == null){
			notificationManager = new NotificationManager(getCore());
		}
		return notificationManager;
	}
	
	public void shutdown() {
		try {
			getCapi().destroyContainer(getSaalContainer(), null);
			getCapi().destroyContainer(getEingangContainer(), null);
			getCapi().destroyContainer(getKuecheInputContainer(), null);
			getCapi().destroyContainer(getKuecheOutputContainer(), null);
			getCapi().destroyContainer(getBestellungNeuContainer(), null);
			getCapi().destroyContainer(getBestellungOffenContainer(), null);
			getCapi().destroyContainer(getBestellungZubContainer(), null);
			getCapi().destroyContainer(getBestellungFertigContainer(), null);
			getCapi().destroyContainer(getZustellungContainer(), null);
			getCapi().destroyContainer(getGruppeSitzenContainer(), null);
			getCapi().destroyContainer(getGruppeWillBestellenContainer(), null);
			getCapi().destroyContainer(getGruppeHatBestelltContainer(), null);
			getCapi().destroyContainer(getGruppeEssenContainer(), null);
			getCapi().destroyContainer(getGruppeWillBezahlenContainer(), null);
			getCapi().destroyContainer(getGruppeHatBezahltContainer(), null);
			getCapi().destroyContainer(getGruppeGegangenContainer(), null);
			
		} catch (MzsCoreException e) {
			logger.error("Shutdown failed.");
		}
		core.shutdown(true);
	}

}
